package com.example.online.music.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.online.music.common.FaceAiUtil;
import com.example.online.music.common.R;
import com.example.online.music.model.domain.Face;
import com.example.online.music.model.domain.UserGroup;
import com.example.online.music.service.IFaceService;
import com.example.online.music.service.IGroupService;
import okhttp3.*;
import okhttp3.RequestBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Base64;
import java.util.Date;
import java.util.Objects;
import static com.example.online.music.model.domain.UserGroup.MAX_NUMBER_OF_EACH_GROUP;

@RestController
@RequestMapping("/face")
@CrossOrigin(origins = "*", maxAge = 3600)
public class FaceController {
    public static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();

    static final String AK = FaceAiUtil.API_KEY;
    static final String SK = FaceAiUtil.SECRET_KEY;

    @Autowired
    IFaceService faceService;
    @Autowired
    IGroupService groupService;

    @GetMapping("/getToken")
    public R getToken() {
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, "");
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/oauth/2.0/token?client_id=" + AK + "&client_secret=" + SK + "&grant_type=client_credentials")
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            return R.success("获取token成功",JSONObject.parseObject(Objects.requireNonNull(response.body()).string()));
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("获取Token失败");
        }
    }

    @PostMapping("/registerFace")
    public R registerFace(MultipartFile file, @RequestParam String token, @RequestParam String groupId, @RequestParam String userId) {
        MediaType mediaType = MediaType.parse("application/json");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("image", getBase64String(file));
        jsonObject.put("image_type", "BASE64");
        jsonObject.put("group_id", groupId);
        jsonObject.put("user_id", userId);

        QueryWrapper<UserGroup> wrapper = new QueryWrapper<>();
        wrapper.eq("group_id", groupId);
        UserGroup group = groupService.getOne(wrapper);
        if (group == null) {
            return R.error("该用户组还未创建, 用户注册失败, 请重新注册");
        }
        if (group.getUserNumber() >= MAX_NUMBER_OF_EACH_GROUP) {
            return R.error("该用户组人数已达到20个, 不能再添加, 请重新选择用户组创建");
        }

        QueryWrapper<Face> faceQueryWrapper = new QueryWrapper<>();
        faceQueryWrapper.eq("group_id", groupId).eq("user_id", userId);
        if (faceService.getOne(faceQueryWrapper) != null) {
            return R.error( "该用户组内的该用户已存在, 用户注册失败, 请重新注册");
        }

        RequestBody body = RequestBody.create(mediaType, jsonObject.toJSONString());
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=" + token)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            JSONObject map = JSONObject.parseObject(Objects.requireNonNull(response.body()).string());
            Integer errorCode = (Integer) map.get("error_code");

            if (errorCode == 0) {
                Face face = new Face();
                JSONObject R_Json = JSONObject.parseObject(map.get("R").toString());
                face.setFaceId(R_Json.get("face_token").toString());
                face.setGroupId(groupId);
                face.setUserId(userId);
                face.setCreateTime(new Date() + "");
                faceService.save(face);

                group.setUserNumber(group.getUserNumber() + 1);
                groupService.update(group, wrapper);

                return R.success("人脸注册成功");
            } else if (errorCode == 223105) {
                return R.error("人脸注册失败, 人脸已存在");
            }

            return R.error("未知错误, 人脸注册失败");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("人脸注册失败");
        }
    }

    @PostMapping("/detect")
    public R detect(MultipartFile file, @RequestParam String token, @RequestParam String groupId, @RequestParam String userId) {
        QueryWrapper<Face> wrapper = new QueryWrapper<>();
        wrapper.eq("group_id", groupId).eq("user_id", userId);
        Face face = faceService.getOne(wrapper);
        if (face == null) {
            return R.error("该用户还未注册, 人脸检测失败");
        }

        JSONObject face1 = new JSONObject();
        face1.put("image", getBase64String(file));
        face1.put("image_type", "BASE64");
        JSONObject face2 = new JSONObject();
        face2.put("image", face.getFaceId());
        face2.put("image_type", "FACE_TOKEN");

        MediaType mediaType = MediaType.parse("application/json");
        JSONArray jsonArray = new JSONArray();
        jsonArray.set(0, face1);
        jsonArray.set(1, face2);

        RequestBody body = RequestBody.create(mediaType, jsonArray.toJSONString());
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=" + token)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .addHeader("Accept", "application/json")
                .build();
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            String string = Objects.requireNonNull(response.body()).string();
            JSONObject map = JSONObject.parseObject(string);
            Integer errorCode = (Integer) map.get("error_code");
            if (errorCode == 0) {
                JSONObject R_Json = JSONObject.parseObject(map.get("R").toString());
                BigDecimal score = (BigDecimal) R_Json.get("score");
                if (score.doubleValue() > Face.MIN_THRESHOLD_VALUE) {
                    return R.success("人脸检测成功");
                } else {
                    return R.success("检测发现人脸不匹配, 人脸检测失败");
                }
            } else if (errorCode == 222202) {
                return R.success(null, "图片中没有人脸, 人脸检测失败");
            } else if (errorCode == 222209) {
                return R.success(null, "face token不存在, 检测的人脸信息还未创建, 人脸检测失败");
            }
            return R.success(null, "未知错误, 人脸检测失败");
        } catch (Exception e) {
            e.printStackTrace();
            return R.error("人脸检测失败");
        }
    }

    public String getBase64String(MultipartFile file) {
        String baseStr;
        try {
            baseStr = Base64.getEncoder().encodeToString(file.getBytes());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        baseStr = baseStr.replaceAll("\r\n", "");
        return baseStr;
    }
}